package org.cnc.app;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.KeyboardFocusManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ServerNotActiveException;

import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.cnc.core.DetailModel;
import org.cnc.core.MachineControl;
import org.cnc.core.MachineControl.Command;
import org.cnc.core.MachineControl.MachineMode;
import org.cnc.machine.CncMachine;
import org.cnc.machine.CutterPosition;
import org.cnc.rmi.interfaces.MachineControlCallbackInterface;
import org.cnc.rmi.interfaces.MachineControlInterface;
import org.cnc.rmi.interfaces.RmiServer;
import org.jvnet.substance.skin.SubstanceRavenGraphiteGlassLookAndFeel;

public class Machine implements ChangeListener {

	public Machine()
	{
		try
		{
			myServer = new Server("machine", 3100);
			
		} catch (RemoteException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		machine_control = new MachineControl();
		
		machine = new CncMachine(machine_control);
		
		machine.addChangeListener(this);
	}
	
	public class MachineModule extends ServerModule<Server>
	{		
		public MachineModule() throws RemoteException,
				ServerNotActiveException
		{
			super( myServer );
			
			machine_panel = new MachinePanel();
			
			this.frame.add( machine_panel, BorderLayout.CENTER );
		}

		
	}
	
	@SuppressWarnings("serial")
	class Server extends RmiServer
	implements MachineControlInterface
	{
		public Server( String name, int port )
				throws RemoteException {
			super( name, port );
		}

		@Override
		public void makeStep(String cmd) {
			Command command = Command.valueOf(cmd);
			machine_control.makeStep(command);
		}

		@Override
		public void makeStep() {
			// TODO Auto-generated method stub
			machine_control.makeStep();
		}

		@Override
		public void setMode(String m) {

			MachineMode mode = MachineMode.valueOf(m);
			
			machine_control.setMode(mode);
		}

		@Override
		public void generateCommands(DetailModel model) {
			machine_control.generateCommands(model);
		}

		@Override
		public void setDelayTime(int delay) {
			machine_control.setDelayTime(delay);
		}

		@SuppressWarnings("deprecation")
		@Override
		public void startMachine() {

			try {
				
				String coreAddress = myServer.getClientAddress();
				
				Registry machineRegistry = LocateRegistry.getRegistry(
						coreAddress,
							(new Integer(5500)).intValue());
				
				callback = (MachineControlCallbackInterface)(machineRegistry.lookup("core"));
			}
			catch ( Exception e )
			{
				e.printStackTrace();
			}
			
			if ( machine != null )
			{
				stopMachine();
			}
			
			if ( machine == null )
				machine = new CncMachine( machine_control );
				
			if ( machine.isAlive() )
				machine.resume();
			else
				machine.start();
			
		}

		@SuppressWarnings("deprecation")
		@Override
		public void stopMachine() {

			machine.suspend();
			
		}

		@Override
		public CutterPosition getCutterPosition() {

			return machine.getCutterPosition();
		}
	}
	
	public static void main( String args[] )
	{
		SwingUtilities.invokeLater ( new Runnable()
		{
			public void run ()
			{
				try
				{
					Machine application = new Machine();
					
				    UIManager.setLookAndFeel (new SubstanceRavenGraphiteGlassLookAndFeel()  );
				    
				    MachineModule drawerModule = application.new MachineModule();
				    
				    KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(drawerModule);
				}
				catch ( Exception e )
				{
				    e.printStackTrace();
				}
			}
		} );
	}
	
	@SuppressWarnings("serial")
	class MachinePanel extends JPanel
	{
		private JLabel lblXY;
		private JLabel lblCommand;
		
		public MachinePanel()
		{
			setBackground(Color.DARK_GRAY);
			
			JScrollPane scrollPane = new JScrollPane();
			
			JLabel lblMachine = new JLabel("Machine");
			lblMachine.setForeground(Color.WHITE);
			lblMachine.setFont(new Font("Tahoma", Font.PLAIN, 18));
			
			lblCommand = new JLabel("COMMAND");
			lblCommand.setHorizontalAlignment(SwingConstants.CENTER);
			lblCommand.setForeground(Color.LIGHT_GRAY);
			lblCommand.setFont(new Font("Tahoma", Font.PLAIN, 48));
			
			JLabel lblCutterPosition = new JLabel("Cutter position:");
			lblCutterPosition.setHorizontalAlignment(SwingConstants.CENTER);
			lblCutterPosition.setForeground(Color.LIGHT_GRAY);
			lblCutterPosition.setFont(new Font("Tahoma", Font.PLAIN, 26));
			
			lblXY = new JLabel("X:0  Y:0  Z:0");
			lblXY.setHorizontalAlignment(SwingConstants.CENTER);
			lblXY.setFont(new Font("Tahoma", Font.PLAIN, 48));
			lblXY.setForeground(Color.LIGHT_GRAY);
			GroupLayout groupLayout = new GroupLayout(this);
			groupLayout.setHorizontalGroup(
				groupLayout.createParallelGroup(Alignment.LEADING)
					.addGroup(groupLayout.createSequentialGroup()
						.addContainerGap()
						.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
							.addComponent(lblCutterPosition, GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE)
							.addComponent(lblCommand, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE)
							.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE)
							.addComponent(lblMachine, GroupLayout.PREFERRED_SIZE, 123, GroupLayout.PREFERRED_SIZE)
							.addComponent(lblXY, GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE))
						.addContainerGap())
			);
			groupLayout.setVerticalGroup(
				groupLayout.createParallelGroup(Alignment.LEADING)
					.addGroup(groupLayout.createSequentialGroup()
						.addContainerGap()
						.addComponent(lblMachine, GroupLayout.PREFERRED_SIZE, 30, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(lblCutterPosition, GroupLayout.PREFERRED_SIZE, 49, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(lblXY, GroupLayout.PREFERRED_SIZE, 59, GroupLayout.PREFERRED_SIZE)
						.addGap(147)
						.addComponent(lblCommand, GroupLayout.PREFERRED_SIZE, 82, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED, 18, Short.MAX_VALUE)
						.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 245, GroupLayout.PREFERRED_SIZE)
						.addContainerGap())
			);
			
			listData = new DefaultListModel();
			JList list = new JList(listData);
			list.setFont(new Font("Tahoma", Font.PLAIN, 26));
			scrollPane.setViewportView(list);
			setLayout(groupLayout);

		}
		
		public void updatePanel( String command )
		{
			lblCommand.setText(command);
			lblXY.setText("X:" + machine.getCutterPosition().x() + " Y:" + machine.getCutterPosition().y() + " Z:" + machine.getCutterPosition().z());
			listData.add(0, "Command: " + command);
		}
	}
	
	private void addLog(String str)
	{
		listData.add(0, str);
	}
	
	// fields
	private CncMachine machine;
	private MachineControl machine_control;
	private DefaultListModel listData;
	private MachinePanel machine_panel;
	private MachineControlCallbackInterface callback;
	private Server myServer;
	
	@Override
	public void stateChanged(ChangeEvent e) {
		
		if (e.getSource() instanceof Command)
		{
			Command cmd = (Command)e.getSource();
			
			machine_panel.updatePanel( cmd.toString() );
			
			try {
				callback.cutterChanged( machine.getCutterPosition() );
			} catch (RemoteException e1) {
				// TODO Auto-generated catch block
				
			}
		}
	}
}